﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Util;
using Word = Microsoft.Office.Interop.Word;

namespace WORD_LIB
{
    public class WordSession
    {
        private static object m = Type.Missing;
        private static object otrue = true;
        private static object ofalse = false;
        private Word.Application word;
        private Word.Document doc;
        public WordSession()
        {
            word = new Word.Application();
        }

        public void Open(string path)
        {
            object opath = (object)path;
            doc = word.Documents.Open(opath, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m);
        }

        public void Save(string path)
        {
            object opath = (object)path;
            doc.SaveAs2(opath, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m);
        }

        public void Close()
        {
            doc.Close(m, m, m);
        }

        public void Quit()
        {
            word.Quit(ofalse, m, m);
        }

        public void Show()
        {
            word.Visible = true;
        }

        public void Hide()
        {
            word.Visible = false;
        }

        int ParagraphIx = int.MinValue;

        private void ValidateParagraphIx(ref int paragraphIx, int max)
        {
            if (paragraphIx < 1) paragraphIx = 1;
            if (paragraphIx > max) paragraphIx = max;
        }

        public List<Tuple<int, int>> sectionsParagraphs = new List<Tuple<int, int>>();
        public List<Tuple<int, int>> sectionsWords = new List<Tuple<int, int>>();

        /// <summary>
        /// en este metodo voy a splitear el word entero en parrafos
        /// </summary>
        public void Split(Func<string, bool> test)
        {
            List<int> sectionBeginParagraphs = new List<int>();
            List<int> sectionBeginWords = new List<int>();
            int wordIx = 1;
            int totalParagraphs = doc.Paragraphs.Count;
            for (int paragraphIx = 1; paragraphIx <= totalParagraphs; paragraphIx++)
            {
                Logger.WriteLine("{0}/{1}", paragraphIx, totalParagraphs);
                var paragraph = doc.Paragraphs[paragraphIx];
                if (test(paragraph.Range.Text))
                {
                    paragraph.Range.HighlightColorIndex = Word.WdColorIndex.wdPink;
                    Logger.WriteLine("Verso encontrado: {0}", paragraph.Range.Text);
                    sectionBeginParagraphs.Add(paragraphIx);
                    sectionBeginWords.Add(wordIx);
                }
                wordIx += paragraph.Range.Words.Count;
            }
            int prev = sectionBeginParagraphs[0];
            sectionBeginParagraphs.RemoveAt(0);
            sectionsParagraphs = sectionBeginParagraphs.Select(x =>
                {
                    var tuple = new Tuple<int, int>(prev, x);
                    prev = x;
                    return tuple;
                }).ToList();
        }

        public List<Tuple<int, int>> Extract(Func<string, bool> test,
            Func<Tuple<string, int, int>, int> getVerseCharsCount,
            Func<string, Tuple<string, int, int>> getShortKey,
            Func<Tuple<string, int, int>, Tuple<string, int, int>> convertToFullKey,
            Func<Tuple<string, int, int>, int> getKeyLength)
        {
            List<Tuple<int, int>> wordFragments = new List<Tuple<int, int>>();
            int charIx = 0;
            int totalParagraphs = doc.Paragraphs.Count;
            for (int paragraphIx = 1; paragraphIx <= totalParagraphs; paragraphIx++)
            {
                Logger.WriteLine("{0}/{1}", paragraphIx, totalParagraphs);
                var paragraph = doc.Paragraphs[paragraphIx];
                string text = paragraph.Range.Text;
                if (test(text))
                {
                    Tuple<string, int, int> key = null;
                    try
                    {
                        key = getShortKey(text);
                        int keyLength = getKeyLength(key);
                        key = convertToFullKey(key);
                        int charsCount = getVerseCharsCount(key);
                        int totalLength = keyLength + 1 + charsCount;
                        int begin = charIx;
                        int end = charIx + totalLength;
                        var range = doc.Range(begin, end);
                        wordFragments.Add(new Tuple<int, int>(begin, end));
                        range.HighlightColorIndex = Word.WdColorIndex.wdPink;
                        Logger.WriteLine("Verso encontrado: {0}", range.Text);
                    }
                    catch
                    {
                        Logger.WriteLine("Falla al buscar el texto NVI: {0} {1}:{2}", key.Item1, key.Item2, key.Item3);
                    }
                }
                charIx += paragraph.Range.Characters.Count;
            }
            return wordFragments;
        }

        public void ReplaceText(Func<string, string> search, Func<string, string> replace)
        {
            sectionsParagraphs.ForEach(x =>
                {
                    var range = doc.Paragraphs[x.Item1].Range;
                    string toReplace = search(range.Text);
                    try
                    {
                        string replacement = replace(toReplace);
                        if (replacement != null)
                        {
                            Logger.WriteLine("Replacing: =================================");
                            Logger.WriteLine("  Original: {0}", toReplace);
                            Logger.WriteLine("Replcement: {0}", replacement);
                            range.Text = range.Text.Replace(toReplace, replacement);
                        }
                    }
                    catch
                    {
                        Logger.WriteLine("Replacing: !! FAIL !!!!!!!!!!!!!!!!!!!!!!!!!");
                        Logger.WriteLine("  Original: {0}", toReplace);
                    }
                });
        }

        public void HighlightText()
        {
            sectionsParagraphs.ForEach(x =>
            {
                var range = doc.Paragraphs[x.Item1].Range;
                range.HighlightColorIndex = Word.WdColorIndex.wdPink;
            });
        }

        //public void NextParagraph()
        //{
        //    if (word != null)
        //    {
        //        ParagraphIx++;
        //        ValidateParagraphIx(ref ParagraphIx, doc.Paragraphs.Count);
        //        ShowParagraph(ParagraphIx);
        //    }
        //}

        public void LoadData(Action<string> action)
        {
            int totalParagraphs = doc.Paragraphs.Count;
            for (int paragraphIx = 1; paragraphIx <= totalParagraphs; paragraphIx++)
            {
                Logger.WriteLine("{0}/{1}", paragraphIx, totalParagraphs);
                var paragraph = doc.Paragraphs[paragraphIx];
                action(paragraph.Range.Text);
            }
        }
    }
}
